#ifndef EASYASIO_NET_UDP_ENDPOINT_HPP
#define EASYASIO_NET_UDP_ENDPOINT_HPP

#ifdef WIN32
#include <Winsock2.h>
#else
#endif

#include <asio.hpp>
#include <list>
#include <memory>
#include <functional>
#include <iostream>

#include "message_decode_buffer.h"
#include "message_encode_buffer.h"

class UdpEndpoint;
typedef std::shared_ptr<UdpEndpoint> SpUdpEndpoint;

typedef std::function<
    void(const SpUdpEndpoint&, const asio::ip::udp::endpoint& remote, const char* buf, size_t len)> MessageCallback;

class UdpEndpoint: public std::enable_shared_from_this<UdpEndpoint>
{
public:

    UdpEndpoint(asio::io_service& io_service, const char* local_addr, int local_port = 0);
    ~UdpEndpoint();
    void start();
    void sendto(const std::string& msg, const char* remote_addr, int remote_port);
    void sendto(const std::string& msg, const asio::ip::udp::endpoint& endpoint);
    void setMessageCallback(const MessageCallback& cb);
    void join_multicast_group(const char* addr);
    void leave_multicast_group(const char* addr);
    void setEncodeBuffer(const std::shared_ptr<MessageEncodeBuffer>& encodebuffer);
    void setDecodeBuffer(const std::shared_ptr<MessageDecodeBuffer>& decodebuffer);

    //²»Ö§³Ö¶¯Ì¬µ÷Õû, ÔÚstartÖ®Ç°µ÷ÓÃ
    void setSendRate(int rateKBs)
    {
        rateKBs_ = rateKBs;
        send_internal_msecs_ = 1000 / (rateKBs * 1000 / 1300);
    }
private:
    struct MsgWrapper;
    typedef std::shared_ptr<MsgWrapper> SpMsgWrapper;
    typedef std::list<SpMsgWrapper> MsgWrapperPtrList;

    void do_asyn_receive();
    void sendtoMessageInloop(const SpMsgWrapper& msgptr);
    void sendToOneMessageInLoop();
    void handle_sendto_complete(const asio::error_code& error, size_t /*bytes_sent*/);
    void handle_receive_from(const asio::error_code& error, size_t bytes_recvd);

    void setSendPkTimer();
    void handleSendPkTimter();
private:
    MessageCallback msg_callback_;
    asio::io_service& io_service_;

    asio::ip::udp::socket socket_;
    asio::ip::udp::endpoint sender_endpoint_;
    enum { max_length = 1500 };
    char data_[max_length];
    
    std::list<SpMsgWrapper> msg_list_;
    std::shared_ptr<MessageDecodeBuffer> msg_decode_buffer_;
    std::shared_ptr<MessageEncodeBuffer> msg_encode_buffer_;

    asio::basic_waitable_timer<std::chrono::system_clock> send_pk_timer_;
    int rateKBs_;
    int send_internal_msecs_;
};

#endif//EASYASIO_NET_UDP_ENDPOINT_HPP